home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / bsd-dyna-link < prev    next >
Encoding:
Internet Message Format  |  1988-05-08  |  57.7 KB

  1. Subject:  v14i089:  Dynamic linking package for BSD
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dave Jones <megatest!djones>
  7. Posting-number: Volume 14, Issue 89
  8. Archive-name: bsd-dyna-link
  9.  
  10. [  I thought about asking for a Makefile and manpage, and probably made
  11.    a mistake in not asking for it.  --r$  ]
  12.  
  13. I made a casual mention of a dynamic linking routine a while back, and
  14. I was overwhelmed with requests for it.  My software manager has kindly
  15. said, okay, let'er rip.
  16.  
  17. DISCLAIMER:
  18. As is usual with free software, neither I nor my employeer assumes any
  19. responsibility at all for these routines.  I hope they work good and
  20. last a long time, but if they don't, don't come whining to me.
  21. And please do not install them as part of anything that shoots.
  22.  
  23. The following routines are for doing dynamic loading under SunOS-3.
  24. You can probably hack it up pretty easily to run under any BSD-related
  25. system.  I don't know off-hand how much the System V a.out format 
  26. and the COFF format are like BSD's a.out.  You might have some trouble 
  27. porting it to one of those.
  28.  
  29. Good luck.
  30.  
  31. And oh, yes.  Please don't call me for support (unless you have something
  32. really fabulous to trade).
  33.  
  34.         Dave Jones
  35.         Megatest Corp.
  36.         880 Fox Lane
  37.         San Jose, CA.
  38.         95131
  39.  
  40.         (408) 437-9700 Ext 3227
  41.         UUCP: ucbvax!sun!megatest!djones
  42.         ARPA: megatest!djones@riacs.ARPA
  43.  
  44. #! /bin/sh
  45. # This is a shell archive.  Remove anything before this line, then unpack
  46. # it by saving it into a file and typing "sh file".  To overwrite existing
  47. # files, type "sh file -c".  You can also feed this as standard input via
  48. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  49. # will see the following message at the end:
  50. #        "End of shell archive."
  51. # Contents:  dyna_link.c dyna_link.doc dyna_link.h assoc.c assoc.doc
  52. #   assoc_internals.h assoc.h which.c smalloc.c argv.c
  53. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  54. if test -f dyna_link.c -a "${1}" != "-c" ; then 
  55.   echo shar: Will not over-write existing file \"dyna_link.c\"
  56. else
  57. echo shar: Extracting \"dyna_link.c\" \(14909 characters\)
  58. sed "s/^X//" >dyna_link.c <<'END_OF_dyna_link.c'
  59. X/*
  60. X**   #include <a.out.h>
  61. X**   #include "assoc.h"
  62. X**   #include "dyna_link.h
  63. X**   
  64. X**   
  65. X**   lk_get_header(fd, hdrp, offset)  /@ reads an a.out header into memory @/
  66. X**      int fd;               /@ an open file-descriptor @/
  67. X**      struct exec *hdrp;    /@ pointer to memory for a.out header @/
  68. X**      long offset;          /@ displacement of file (for archives)@/
  69. X**
  70. X**   lk_get_symbols(fd, hdrp, offset)  /@ Reads symbols into memory @/
  71. X**      int fd;               /@ an open file-descriptor @/
  72. X**      struct exec *hdrp;    /@ pointer to previously initialized header @/
  73. X**      long offset;          /@ displacement of file (for archives) @/
  74. X**
  75. X**   assoc_mem
  76. X**   lk_sym_hash(hdrp, syms); /@ Creates lookup-table for symbols @/
  77. X**      struct exec *hdrp;    /@ pointer to previously initialized header @/
  78. X**      struct nlist *syms;   /@ pointer to previously initialized symbols @/
  79. X**
  80. X**   func_ptr 
  81. X**   lk_dynaload(codep, hdrp, hash_table, filename) /@ loads named file @/
  82. X**      int* codep;           /@ pointer to memory for return-code @/
  83. X**      struct exec* hdrp;    /@ pointer to previously initialized header @/
  84. X**      assoc_mem hash_table; /@ previously initialized lookup-table @/
  85. X**      char* filename;
  86. X**
  87. X**   func_ptr  /@ loads a file, given by file-descriptor and offset. @/
  88. X**   lk_dynaload_fd(codep, hdrp, hash_tab, fd, offset)
  89. X**     int *codep;            /@ pointer to memory for return-code @/
  90. X**     struct exec *hdrp;     /@ pointer to previously initialized header @/
  91. X**     assoc_mem hash_tab;    /@ previously initialized lookup-table @/
  92. X**     int fd;                /@ an open file-descriptor @/
  93. X**     long disp;             /@ displacement of file (for archives) @/
  94. X**
  95. X**   This library furnishes routines for doing a dynamic load of an executable
  96. X**   segment ( .o file).
  97. X**
  98. X**   The caller first must build a lookup-table for the symbols
  99. X**   of the executing program.  (See assoc.doc for description
  100. X**   of lookup-table routines.)
  101. X**
  102. X**   Once the lookup-table has been made, the program may repeatedly call
  103. X**   lk_dynaload() or lk_dynaload_fd() to load segments.
  104. X**   Loaded segments may be freed using free().
  105. X**
  106. X**   The routines to be used for building the lookup-table are
  107. X**   lk_get_header(), lk_get_symbols(), and lk_sym_hash().  These are
  108. X**   also potentially useful for other link-editor applications, and
  109. X**   for that reason are parameterized so that they may be used on
  110. X**   archive members, as well as on individual a.out files.
  111. X**
  112. X**   lk_get_header() returns 0 on success, -1 on failure.  Sets errno.
  113. X**
  114. X**   lk_get_symbols() returns a buffer from malloc() on success, null
  115. X**     on failure.  Sets errno.
  116. X**
  117. X**   lk_sym_hash() returns an assoc_mem on success (see assoc.doc), null
  118. X**     on failure.  Sets errno.
  119. X**
  120. X**   lk_dynaload() and lk_dynaload_fd() return a pointer to the entry-point
  121. X**     of the .o file on success, null on failure.  Sets *codep (see
  122. X**     parameters).  The values for *codep are defined in dyna_link.h:
  123. X**
  124. X**      #define lk_ok 0
  125. X**      #define lk_undefd 1
  126. X**      #define lk_bad_format 2
  127. X**      #define lk_perror -1
  128. X**
  129. X**   lk_ok means "okay."
  130. X**   lk_undefd means that one or more symbols required by the .o file
  131. X**     are not defined in the lookup-table.  In this case the char**
  132. X**     lk_undefined will have been set to point to a vector containing
  133. X**     the undefined symbols.
  134. X**   lk_bad_format means that the .o file is not formatted occording
  135. X**     to the a.out file conventions.
  136. X**   lk_perror means that errno has been set.
  137. X**
  138. X**  
  139. X**   Tutorial example:
  140. X**
  141. X**   main(argc, argv)
  142. X**     char** argv;
  143. X**   {
  144. X**     char* me = (char*) which(argv[0]);
  145. X**     char* prog = (char*)(argv[1]);
  146. X**     func_ptr entry_point;
  147. X**     assoc_mem hash_tab;
  148. X**     struct exec main_hdr;
  149. X**     struct nlist * main_syms;
  150. X**     int code;
  151. X**     int fd = open( me, O_RDONLY );
  152. X**   
  153. X**     lk_get_header(fd, &main_hdr, 0 );
  154. X**     main_syms = lk_get_symbols(fd, &main_hdr, 0 );
  155. X**     close(fd);
  156. X**     hash_tab = lk_sym_hash(&main_hdr, main_syms);
  157. X**   
  158. X**     (func_ptr) entry_point
  159. X**                 = lk_dynaload( &code, &main_hdr, hash_tab, prog );
  160. X**     if(entry_point)
  161. X**           (*(func_ptr) entry_point)();
  162. X**     else
  163. X**        switch(code)
  164. X**           {
  165. X**           case lk_undefd:
  166. X**             { char** undef = lk_undefined;
  167. X**           printf("undefined:\n");
  168. X**           while(*undef) printf("%s\n", *undef++);
  169. X**             }
  170. X**             break;
  171. X**           case lk_perror:
  172. X**             perror(prog);
  173. X**             break;
  174. X**           case lk_bad_format:
  175. X**             printf("bad format\n");
  176. X**             break;
  177. X**           }
  178. X**         }
  179. X**     }
  180. X**     exit(0);
  181. X**   }
  182. X**   
  183. X*/
  184. X
  185. X
  186. X#include <stdio.h>
  187. X#include <a.out.h>
  188. X#include <sys/file.h>
  189. X#include <sys/types.h>
  190. X#include <errno.h>
  191. X#include <sys/stat.h>
  192. X#include <ctype.h>
  193. X
  194. X#include "assoc.h"
  195. X#include "dyna_link.h"
  196. X
  197. Xlk_get_header(fd, hdrp, disp)
  198. X  int fd;
  199. X  struct exec *hdrp;
  200. X  long disp;
  201. X{
  202. X  lseek(fd, disp, 0);
  203. X  if (read(fd, hdrp, sizeof(struct exec)) != sizeof(struct exec))
  204. X    {hdrp->a_magic = 0;  return -1; }
  205. X  return 0;
  206. X}
  207. X
  208. X/* This routine buffers up the symbols and strings from a file. */
  209. X/* Converts file-displacements of strings to pointers.          */
  210. Xstruct nlist *
  211. Xlk_get_symbols(fd, hdrp, disp)
  212. X  int fd;
  213. X  struct exec *hdrp;
  214. X  long disp;
  215. X{
  216. X  struct nlist * buffer;
  217. X  unsigned long size;
  218. X
  219. X  if(N_BADMAG(*hdrp))
  220. X    { errno = ENOEXEC;
  221. X      return 0;
  222. X    }
  223. X
  224. X  lseek(fd, disp + N_SYMOFF(*hdrp) + hdrp->a_syms, 0);
  225. X  if(read(fd, &size, 4) != 4)
  226. X    return 0;
  227. X
  228. X  buffer = (struct nlist*) malloc(hdrp->a_syms + size);
  229. X  if(buffer == 0) return 0;
  230. X  
  231. X  lseek(fd, disp + N_SYMOFF(*hdrp), 0);
  232. X  if(read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size)
  233. X    { free(buffer);
  234. X      return 0;
  235. X    }
  236. X  
  237. X  {
  238. X    struct nlist * sym = buffer;
  239. X    struct nlist * end = sym + hdrp->a_syms / sizeof(struct nlist);
  240. X    long displ = (long)buffer + (long)(hdrp->a_syms);
  241. X
  242. X    while(sym < end)
  243. X      {
  244. X    sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
  245. X    sym++;
  246. X      }
  247. X  }
  248. X  return buffer;
  249. X  
  250. X}
  251. Xstatic file_size;
  252. X
  253. X/* Buffers up relocation info */
  254. Xstruct relocation_info *
  255. Xlk_get_reloc(fd, hdrp, disp)
  256. X     int fd;
  257. X     struct exec *hdrp;
  258. X     long disp;
  259. X{
  260. X  struct relocation_info * buffer;
  261. X  int size;
  262. X
  263. X
  264. X  if(N_BADMAG(*hdrp))
  265. X    { errno = ENOEXEC;
  266. X      return 0;
  267. X    }
  268. X  
  269. X  lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
  270. X  
  271. X  size = hdrp->a_trsize + hdrp->a_drsize;
  272. X  buffer = (struct relocation_info*) malloc( size );
  273. X
  274. X  if(buffer == 0) return 0;
  275. X  
  276. X  if(read(fd, buffer, size) !=  size)
  277. X    { free(buffer);
  278. X      return 0;
  279. X    }
  280. X  
  281. X  return buffer;
  282. X  
  283. X}
  284. X
  285. X/* Buffers up text and data */
  286. Xstatic
  287. Xunsigned char *
  288. Xlk_get_text_and_data(fd, hdrp, bss, disp )
  289. X  int fd;
  290. X  struct exec *hdrp;
  291. X  int bss; /* -1 iff we should allocate hdrp->a_bss extra space,
  292. X       ** larger numbers indicate extra space to allocate
  293. X       */
  294. X  long disp;
  295. X{
  296. X  unsigned char * buffer;
  297. X  int size;
  298. X
  299. X  if(N_BADMAG(*hdrp))
  300. X    {
  301. X      errno = ENOEXEC;
  302. X      return 0;
  303. X    }
  304. X  
  305. X  lseek(fd, disp + N_TXTOFF(*hdrp), 0);
  306. X  
  307. X  size = hdrp->a_text + hdrp->a_data;
  308. X
  309. X  if(bss == -1) size += hdrp->a_bss;
  310. X  else if (bss > 1) size += bss;
  311. X
  312. X  buffer = (unsigned char*) malloc( size );
  313. X  
  314. X  if(buffer == 0) return 0;
  315. X  
  316. X  if(read(fd, buffer, size) !=  size)
  317. X    { free(buffer);
  318. X      return 0;
  319. X    }
  320. X
  321. X  if(bss == -1)
  322. X    bzero(buffer +  hdrp->a_text + hdrp->a_data, hdrp->a_bss);
  323. X  else if(bss > 0)
  324. X    bzero(buffer +  hdrp->a_text + hdrp->a_data, bss );
  325. X
  326. X  return buffer;
  327. X  
  328. X}
  329. X
  330. Xchar** lk_undefined = 0;
  331. X
  332. Xfunc_ptr
  333. Xlk_dynaload_fd(codep, hdrp, hash_tab, fd, disp)
  334. X  int *codep;
  335. X  struct exec *hdrp;
  336. X  assoc_mem hash_tab;
  337. X  int fd;
  338. X  long disp;
  339. X{
  340. X  func_ptr retval = 0;
  341. X  unsigned char* text_data_bss;
  342. X  struct exec header;
  343. X  struct nlist * symbols = 0;
  344. X  struct relocation_info * reloc = 0;
  345. X  long new_common = 0; /* Length of new common */
  346. X  assoc_mem lk_sym_hash();
  347. X  int undefineds = 0;
  348. X  char*** argv_h = 0;
  349. X
  350. X  *codep = 0;
  351. X
  352. X  if(fd < 0) { *codep = lk_perror; goto end; }
  353. X
  354. X  if(  lk_get_header(fd, &header, 0) != 0
  355. X     ||(reloc = lk_get_reloc(fd, &header, 0)) == 0
  356. X     ||(symbols = lk_get_symbols(fd, &header, 0 )) == 0
  357. X    )
  358. X    { *codep = lk_perror; goto end; }
  359. X
  360. X
  361. X  if(  header.a_magic != 0x107 )
  362. X    { *codep = lk_bad_format; goto end; }
  363. X
  364. X  /* First we will buzz through the new symbols, resolving them.
  365. X  */
  366. X  { struct nlist * symbol = symbols;
  367. X    struct nlist * endp = symbols + (header.a_syms / sizeof(struct nlist));
  368. X    long last_value = new_common;
  369. X    while(symbol < endp)
  370. X      { int type;
  371. X    int value;
  372. X    struct nlist * old_symbol = 0;
  373. X    struct nlist ** old_symbol_p = 0;
  374. X
  375. X    type = symbol->n_type;
  376. X        value = symbol->n_value;
  377. X
  378. X    if(type == N_EXT + N_UNDF )
  379. X      { /* is not defined here yet. */
  380. X          old_symbol_p = (struct nlist **)
  381. X          assoc_lookup(symbol->n_un.n_name, hash_tab);
  382. X
  383. X        if(old_symbol_p) old_symbol = *old_symbol_p;
  384. X
  385. X        if(value != 0)
  386. X          { /* is common */
  387. X        if(old_symbol == 0)
  388. X          { /* is new common */
  389. X            int rnd =
  390. X              value >= sizeof(double) ? sizeof(double) - 1
  391. X            : value >= sizeof(long) ? sizeof(long) - 1
  392. X              : sizeof(short) - 1;
  393. X
  394. X            symbol->n_type = N_COMM;
  395. X            new_common += rnd;
  396. X            new_common &= ~(long)rnd;
  397. X            symbol->n_value = new_common;
  398. X            new_common += value;
  399. X          }
  400. X        else
  401. X          { /* Is old common */
  402. X
  403. X            symbol->n_type = N_EXT + N_COMM;
  404. X            symbol->n_value = old_symbol -> n_value;
  405. X          }
  406. X        last_value = symbol->n_value;
  407. X          } /* end .. is common */
  408. X        else
  409. X          { /* is extern */
  410. X        if(old_symbol == 0)
  411. X          { /* symbol is unresolved. Sigh. */
  412. X            /* But will will keep on going, looking for others. */
  413. X            if(argv_h == 0)
  414. X              argv_h = (char***) argv_new();
  415. X            argv_put(argv_h, symbol->n_un.n_name);
  416. X            undefineds = 1;
  417. X          }
  418. X        else
  419. X          {
  420. X            symbol->n_type = N_EXT + N_COMM;
  421. X            symbol->n_value = old_symbol -> n_value;
  422. X            last_value = symbol->n_value;
  423. X          }
  424. X          }
  425. X      } /* end.. is undefined */
  426. X
  427. X#       ifdef do_stabs
  428. X    if(type&N_EXT && type&N_TYPE == N_UNDF && type&N_STAB)
  429. X      {
  430. X        symbol->n_value = last_value;
  431. X        symbol->n_type = (type&N_STAB) | (N_EXT+N_COMM);
  432. X      }
  433. X#       endif
  434. X    symbol++;    
  435. X      }
  436. X  } /* end buzz */
  437. X
  438. X  if(undefineds) { goto end; }
  439. X  retval = (func_ptr)lk_get_text_and_data(fd, &header, header.a_bss + new_common, 0 );
  440. X
  441. X
  442. X  /* Now zip through relocation data, doing our stuff. 
  443. X  ** First comes the text-relocation
  444. X  */
  445. X  {
  446. X    struct relocation_info * rel = reloc;
  447. X    struct relocation_info * first_data =
  448. X      reloc + 
  449. X    (header.a_trsize  / sizeof(struct relocation_info));
  450. X
  451. X    struct relocation_info * endp =
  452. X      reloc + 
  453. X    (header.a_trsize + header.a_drsize )/ sizeof(struct relocation_info);
  454. X
  455. X    while(rel < endp )
  456. X      {
  457. X    
  458. X    char *address = 
  459. X      (char*) (rel->r_address + (long)retval);
  460. X
  461. X    long datum;
  462. X
  463. X    if(rel >= first_data)
  464. X      address += header.a_text;
  465. X    
  466. X    switch (rel->r_length)
  467. X      {
  468. X      case 0:        /* byte */
  469. X        datum = *address;
  470. X        break;
  471. X        
  472. X      case 1:        /* word */
  473. X        datum = *(short *)address;
  474. X        break;
  475. X        
  476. X      case 2:        /* long */
  477. X        datum = *(long *)address;
  478. X        break;
  479. X        
  480. X      default:
  481. X        { *codep = lk_bad_format;
  482. X          goto end;
  483. X        }
  484. X
  485. X      }
  486. X        
  487. X    if(rel->r_extern)
  488. X      { /* Look it up in symbol-table */
  489. X        struct nlist * symbol = &(symbols[rel->r_symbolnum]);
  490. X        int type = symbol->n_type;
  491. X        char* name = symbol->n_un.n_name;
  492. X        int value = symbol->n_value;
  493. X
  494. X        if(symbol->n_type == N_EXT + N_COMM)
  495. X          /* old common or external */
  496. X           datum += symbol->n_value;
  497. X        else if (symbol->n_type == N_COMM)
  498. X          /* new common */
  499. X          datum += (long)retval + header.a_text + header.a_data;
  500. X        else {  *codep = lk_bad_format; goto end; }
  501. X      } /* end.. look it up */
  502. X    else
  503. X      { /* is static */
  504. X        switch(rel->r_symbolnum & N_TYPE)
  505. X          {
  506. X          case N_TEXT: case N_DATA:
  507. X        datum += (long)retval;
  508. X        break;
  509. X          case N_BSS:
  510. X        datum += (long)retval +  new_common;
  511. X        break;
  512. X          case N_ABS:
  513. X        break;
  514. X          }
  515. X      } /* end .. is static */
  516. X    if(rel->r_pcrel) datum -= (long)retval;
  517. X
  518. X    switch (rel->r_length) {
  519. X      
  520. X    case 0:        /* byte */
  521. X      if (datum < -128 || datum > 127)
  522. X        { 
  523. X          *codep = lk_bad_format; goto end;
  524. X        }
  525. X      *address = datum;
  526. X      break;
  527. X    case 1:        /* word */
  528. X      if (datum < -32768 || datum > 32767)
  529. X        { 
  530. X          *codep = lk_bad_format; goto end;
  531. X        }
  532. X      *(short *)address = datum;
  533. X      break;
  534. X    case 2:        /* long */
  535. X      *(long *)address = datum;
  536. X      break;
  537. X    }
  538. X    rel++;
  539. X      }
  540. X    
  541. X  } /* end.. zip */
  542. X
  543. X end:
  544. X
  545. X  sfree(reloc); sfree(symbols);
  546. X
  547. X  if(*codep != 0) { sfree(retval); retval = 0; }
  548. X  if(undefineds)
  549. X    { *codep = lk_undefd;
  550. X      sfree(lk_undefined);
  551. X      lk_undefined = *argv_h;
  552. X      free(argv_h);
  553. X    }
  554. X  return retval;
  555. X
  556. X}
  557. X
  558. Xfunc_ptr
  559. Xlk_dynaload( codep, hdrp, hash_tab, filename )
  560. X  int *codep;
  561. X  struct exec *hdrp;
  562. X  assoc_mem hash_tab;
  563. X  char* filename;
  564. X{
  565. X
  566. X  int fd = open(filename, O_RDONLY );
  567. X  func_ptr retval = lk_dynaload_fd(codep, hdrp, hash_tab, fd, 0); 
  568. X
  569. X  if(fd >= 0) close(fd);
  570. X  return retval;
  571. X  
  572. X}
  573. X
  574. Xassoc_mem
  575. Xlk_sym_hash(hdrp, syms)
  576. X  struct exec * hdrp;
  577. X  struct nlist * syms;
  578. X{
  579. X  assoc_mem result = new_assoc_mem(sizeof(struct nlist*));
  580. X
  581. X  if(result == 0) return 0;
  582. X
  583. X  {
  584. X    struct nlist * sym = syms;
  585. X    struct nlist * end = syms + (hdrp->a_syms / sizeof(struct nlist));
  586. X
  587. X    while(sym < end)
  588. X      {
  589. X    struct nlist ** ptr = (struct nlist**) assoc(sym->n_un.n_name, result);
  590. X    if(ptr == 0) return 0;
  591. X    *ptr = sym;
  592. X    sym++;
  593. X      }
  594. X  }
  595. X  return result;
  596. X}
  597. X
  598. X#undef demo_dyna_link
  599. X
  600. X#ifdef demo_dyna_link
  601. Xmain(argc, argv)
  602. X  char** argv;
  603. X{
  604. X  char* me = (char*) which(argv[0]);
  605. X  char* prog = (char*)(argv[1]);
  606. X  func_ptr tion;
  607. X  assoc_mem hash_tab;
  608. X  struct exec main_hdr;
  609. X  struct nlist * main_syms;
  610. X
  611. X  int fd = open( me, O_RDONLY );
  612. X
  613. X  lk_get_header(fd, &main_hdr, 0 );
  614. X  main_syms = lk_get_symbols(fd, &main_hdr, 0 );
  615. X  close(fd);
  616. X  hash_tab = lk_sym_hash(&main_hdr, main_syms);
  617. X
  618. X  { int times;
  619. X    int code;
  620. X
  621. X    if(argc==2) times = 1;
  622. X      else times = atoi(argv[2]);
  623. X
  624. X    while(times--)
  625. X      {
  626. X#       include <sys/time.h>
  627. X    struct timeval t1, t2;
  628. X    struct timezone tz;
  629. X    long usecs;
  630. X    gettimeofday(&t1, &tz);
  631. X    (func_ptr)tion = lk_dynaload( &code, &main_hdr, hash_tab, prog );
  632. X    gettimeofday(&t2, &tz);
  633. X
  634. X    usecs =( t2.tv_sec - t1.tv_sec ) * 1000000 + t2.tv_usec - t1.tv_usec;
  635. X/*    fprintf(stderr, "%d %d %d\n", usecs, t2.tv_sec - t1.tv_sec,
  636. X        t2.tv_usec - t1.tv_usec);
  637. X*/
  638. X    if(tion)
  639. X      (*(func_ptr)tion)();
  640. X    else
  641. X      switch(code)
  642. X        {
  643. X        case lk_undefd:
  644. X          { char** undef = lk_undefined;
  645. X        printf("undefined:\n");
  646. X        while(*undef) printf("%s\n", *undef++);
  647. X          }
  648. X          break;
  649. X        case lk_perror:
  650. X          perror(prog);
  651. X          break;
  652. X        case lk_bad_format:
  653. X          printf("bad format\n");
  654. X          break;
  655. X        }
  656. X      }
  657. X  }
  658. X  exit(0);
  659. X}
  660. X
  661. Xint xstderr;
  662. Xint xfprintf;
  663. X
  664. Xkluge() { printf(); }
  665. X
  666. Xint comm_main;
  667. Xint ext;
  668. Xfoo()
  669. X{
  670. X  fprintf(stderr, "(%x %x)foo be called.\n", stderr, fprintf);
  671. X  fprintf(stderr, "(%x %x) <<\n", xstderr, xfprintf);
  672. X}
  673. X
  674. X#endif demo_dyna_link
  675. END_OF_dyna_link.c
  676. if test 14909 -ne `wc -c <dyna_link.c`; then
  677.     echo shar: \"dyna_link.c\" unpacked with wrong size!
  678. fi
  679. # end of overwriting check
  680. fi
  681. if test -f dyna_link.doc -a "${1}" != "-c" ; then 
  682.   echo shar: Will not over-write existing file \"dyna_link.doc\"
  683. else
  684. echo shar: Extracting \"dyna_link.doc\" \(4389 characters\)
  685. sed "s/^X//" >dyna_link.doc <<'END_OF_dyna_link.doc'
  686. X   #include <a.out.h>
  687. X   #include "assoc.h"
  688. X   #include "dyna_link.h
  689. X   
  690. X   
  691. X   lk_get_header(fd, hdrp, offset)  /@ reads an a.out header into memory @/
  692. X      int fd;               /@ an open file-descriptor @/
  693. X      struct exec *hdrp;    /@ pointer to memory for a.out header @/
  694. X      long offset;          /@ displacement of file (for archives)@/
  695. X
  696. X   lk_get_symbols(fd, hdrp, offset)  /@ Reads symbols into memory @/
  697. X      int fd;               /@ an open file-descriptor @/
  698. X      struct exec *hdrp;    /@ pointer to previously initialized header @/
  699. X      long offset;          /@ displacement of file (for archives) @/
  700. X
  701. X   assoc_mem
  702. X   lk_sym_hash(hdrp, syms); /@ Creates lookup-table for symbols @/
  703. X      struct exec *hdrp;    /@ pointer to previously initialized header @/
  704. X      struct nlist *syms;   /@ pointer to previously initialized symbols @/
  705. X
  706. X   func_ptr 
  707. X   lk_dynaload(codep, hdrp, hash_table, filename) /@ loads named file @/
  708. X      int* codep;           /@ pointer to memory for return-code @/
  709. X      struct exec* hdrp;    /@ pointer to previously initialized header @/
  710. X      assoc_mem hash_table; /@ previously initialized lookup-table @/
  711. X      char* filename;
  712. X
  713. X   func_ptr  /@ loads a file, given by file-descriptor and offset. @/
  714. X   lk_dynaload_fd(codep, hdrp, hash_tab, fd, offset)
  715. X     int *codep;            /@ pointer to memory for return-code @/
  716. X     struct exec *hdrp;     /@ pointer to previously initialized header @/
  717. X     assoc_mem hash_tab;    /@ previously initialized lookup-table @/
  718. X     int fd;                /@ an open file-descriptor @/
  719. X     long disp;             /@ displacement of file (for archives) @/
  720. X
  721. X   This library furnishes routines for doing a dynamic load of an executable
  722. X   segment ( .o file).
  723. X
  724. X   The caller first must build a lookup-table for the symbols
  725. X   of the executing program.  (See assoc.doc for description
  726. X   of lookup-table routines.)
  727. X
  728. X   Once the lookup-table has been made, the program may repeatedly call
  729. X   lk_dynaload() or lk_dynaload_fd() to load segments.
  730. X   Loaded segments may be freed using free().
  731. X
  732. X   The routines to be used for building the lookup-table are
  733. X   lk_get_header(), lk_get_symbols(), and lk_sym_hash().  These are
  734. X   also potentially useful for other link-editor applications, and
  735. X   for that reason are parameterized so that they may be used on
  736. X   archive members, as well as on individual a.out files.
  737. X
  738. X   lk_get_header() returns 0 on success, -1 on failure.  Sets errno.
  739. X
  740. X   lk_get_symbols() returns a buffer from malloc() on success, null
  741. X     on failure.  Sets errno.
  742. X
  743. X   lk_sym_hash() returns an assoc_mem on success (see assoc.doc), null
  744. X     on failure.  Sets errno.
  745. X
  746. X   lk_dynaload() and lk_dynaload_fd() return a pointer to the entry-point
  747. X     of the .o file on success, null on failure.  Sets *codep (see
  748. X     parameters).  The values for *codep are defined in dyna_link.h:
  749. X
  750. X      #define lk_ok 0
  751. X      #define lk_undefd 1
  752. X      #define lk_bad_format 2
  753. X      #define lk_perror -1
  754. X
  755. X   lk_ok means "okay."
  756. X   lk_undefd means that one or more symbols required by the .o file
  757. X     are not defined in the lookup-table.  In this case the char
  758. X     lk_undefined will have been set to point to a vector containing
  759. X     the undefined symbols.
  760. X   lk_bad_format means that the .o file is not formatted occording
  761. X     to the a.out file conventions.
  762. X   lk_perror means that errno has been set.
  763. X
  764. X  
  765. X   Tutorial example:
  766. X
  767. X   main(argc, argv)
  768. X     char argv;
  769. X   {
  770. X     char* me = (char*) (argv[0]);
  771. X     char* prog = (char*)(argv[1]);
  772. X     func_ptr entry_point;
  773. X     assoc_mem hash_tab;
  774. X     struct exec main_hdr;
  775. X     struct nlist * main_syms;
  776. X     int code;
  777. X     int fd = open( me, O_RDONLY );
  778. X   
  779. X     lk_get_header(fd, &main_hdr, 0 );
  780. X     main_syms = lk_get_symbols(fd, &main_hdr, 0 );
  781. X     close(fd);
  782. X     hash_tab = lk_sym_hash(&main_hdr, main_syms);
  783. X   
  784. X     (func_ptr) entry_point
  785. X          = lk_dynaload( &code, &main_hdr, hash_tab, prog );
  786. X     if(entry_point)
  787. X       (*(func_ptr) entry_point)();
  788. X     else
  789. X        switch(code)
  790. X           {
  791. X           case lk_undefd:
  792. X             { char undef = lk_undefined;
  793. X           printf("undefined:\n");
  794. X           while(*undef) printf("%s\n", *undef++);
  795. X             }
  796. X             break;
  797. X           case lk_perror:
  798. X             perror(prog);
  799. X             break;
  800. X           case lk_bad_format:
  801. X             printf("bad format\n");
  802. X             break;
  803. X           }
  804. X         }
  805. X     }
  806. X     exit(0);
  807. X   }
  808. X   
  809. X*/
  810. END_OF_dyna_link.doc
  811. if test 4389 -ne `wc -c <dyna_link.doc`; then
  812.     echo shar: \"dyna_link.doc\" unpacked with wrong size!
  813. fi
  814. # end of overwriting check
  815. fi
  816. if test -f dyna_link.h -a "${1}" != "-c" ; then 
  817.   echo shar: Will not over-write existing file \"dyna_link.h\"
  818. else
  819. echo shar: Extracting \"dyna_link.h\" \(276 characters\)
  820. sed "s/^X//" >dyna_link.h <<'END_OF_dyna_link.h'
  821. X
  822. Xtypedef int ((*func_ptr)());
  823. X
  824. X#define lk_undefd 1
  825. X#define lk_bad_format 2
  826. X#define lk_ok 0
  827. X#define lk_perror -1
  828. X
  829. Xextern char** lk_undefined;
  830. X
  831. Xfunc_ptr dynaload();
  832. X
  833. Xassoc_mem
  834. Xlk_sym_hash();
  835. X
  836. Xstruct nlist *
  837. Xlk_get_symbols();
  838. X
  839. Xfunc_ptr
  840. Xlk_dynaload();
  841. X
  842. Xfunc_ptr
  843. Xlk_dynaload_fd();
  844. END_OF_dyna_link.h
  845. if test 276 -ne `wc -c <dyna_link.h`; then
  846.     echo shar: \"dyna_link.h\" unpacked with wrong size!
  847. fi
  848. # end of overwriting check
  849. fi
  850. if test -f assoc.c -a "${1}" != "-c" ; then 
  851.   echo shar: Will not over-write existing file \"assoc.c\"
  852. else
  853. echo shar: Extracting \"assoc.c\" \(17401 characters\)
  854. sed "s/^X//" >assoc.c <<'END_OF_assoc.c'
  855. X#include <ctype.h>
  856. X#include <stdio.h>
  857. X
  858. X
  859. X#define PANIC_FILE stderr
  860. X#include "assoc.h"
  861. X
  862. Xint* H_getmem();
  863. Xint* assoc_lookup();
  864. X
  865. X
  866. X#define LOWER(ch) (isupper(ch)? tolower(ch) : (ch))
  867. X
  868. X/************************************************************************\
  869. X**************************************************************************
  870. X**                                    **
  871. X**  This package uses hash tables to implement an associative memory,    **
  872. X**  or "name table".  See also "assoc.h" and "assoc_internals.h".    **
  873. X**                                    **
  874. X**  The user may associate names, also called "index strings" with    **
  875. X**  packets of memory, called "mem_cell"s, which come in fixed sizes.    **
  876. X**  Then if you know the name, you can look up the mem_cell or vice    **
  877. X**  versa.                                **
  878. X**                                    **
  879. X**  The collision recovery mechanism is a nifty little scheme           **
  880. X**  of my own invention, which I call "linear-congruential rehash",    **
  881. X**  which means "add one and multiply by three".            **
  882. X**                                    **
  883. X**  The orbit of the rehash function touches exactly half the entries    **
  884. X**  in the table, and the table is never allowed to be over half full,  **
  885. X**  so there will always be an empty slot for a new entry.        **
  886. X**  Removing entries is a little bit tricky. Since the lookup mechanism **
  887. X**  stops and reports failure when it comes to an empty slot in the     **
  888. X**  rehash orbit for the value searched for, when an entry is removed,    **
  889. X**  the values in the same orbit which are there as a result of a     **
  890. X**  collision must be backed up to fill the evacuated slot.          **
  891. X**  The entry number is also there for removing entries.  It provides a **
  892. X**  reference back to the slot which points to the entry.        **
  893. X**                                                                      **
  894. X**  We assume that our machine uses two's complement arithmetic.    **
  895. X**************************************************************************
  896. X\************************************************************************/
  897. X
  898. X/**************************************************************************
  899. X**
  900. X**  An entry looks like this:
  901. X**
  902. X**
  903. X**  [pointers]      [pointees]
  904. X**
  905. X**          ------------------
  906. X**  mem         -> |  entry number  |  index of entry into hash table.
  907. X**          ------------------
  908. X**  mem_cell ->    |             |
  909. X**  (slot)    |         |
  910. X**        | user's goodies |  of size table->value_size
  911. X**            |         |
  912. X**        ------------------
  913. X**  string   -> |         |
  914. X**        |  index string  |
  915. X**        |         |
  916. X**        |         |
  917. X**        ------------------
  918. X**
  919. X**
  920. X**  See string_from_cell(), cell_from_string(), mem_from_cell(), and
  921. X**  cell_from_mem().. all macros.
  922. X**
  923. X\*************************************************************************/
  924. X
  925. X
  926. X
  927. X
  928. X
  929. X
  930. X
  931. X/* N.B. The routine assoc() depends on the fact that if a table is less
  932. X** than half full, the rehash orbit will always find an empty slot.
  933. X** This rehash will hit exactly half the slots before it repeats, provided
  934. X** that the table length is a power of two.
  935. X*/
  936. X#define REHASH(hash,table) (((hash+1)*3) & table -> mask)
  937. X
  938. X
  939. X
  940. X
  941. X/**** factory-procedure, makes new tables. ****/
  942. X
  943. Xassoc_mem
  944. Xnew_assoc_mem(value_size)
  945. X  int value_size; /* storage size of values to be in assoc mem */
  946. X{
  947. X  register assoc_mem table;
  948. X
  949. X  table = (assoc_mem) H_getmem(sizeof (struct assoc_mem_rec));
  950. X
  951. X  table->value_size = value_size;
  952. X  table->entries = 0;
  953. X  table->size = INIT_TABLE_SIZE;
  954. X  table->size_div_2 = table->size / 2;
  955. X  table->mask = table->size -1;
  956. X  table->array = (hash_table *)H_getmem(table->size * (sizeof (mem_cell)));
  957. X
  958. X  return table;
  959. X}
  960. X
  961. X
  962. X
  963. X/* Associates a name with a new mem_cell, or return pointers to previously
  964. X** associated cell.  Initializes new cells to all zero, so you may determine 
  965. X** whether or not a cell is new by smudging a "virgin-bit" when you
  966. X** first obtain a new cell.  If you get a cell from assoc() with a
  967. X** fresh new virgin bit, then the cell must be a new one.
  968. X*/
  969. X
  970. X
  971. Xmem_cell
  972. Xassoc( string, table)
  973. X  register char* string;
  974. X  register assoc_mem table;
  975. X{ /* assoc */
  976. X
  977. X  int length;
  978. X  int hashval;
  979. X
  980. X  register int   rehash;
  981. X  register entry assoc_value;
  982. X
  983. X  /* This is essential.  See assoc_internals.h */
  984. X  if (table->entries >= table->size_div_2 - 1)
  985. X    H_expand_table(table);
  986. X
  987. X  hash(string, table->mask, &length, &hashval);
  988. X  rehash = hashval;
  989. X
  990. X look_at_slot:
  991. X  {  register entry * slot = &((*(table->array))[rehash]);
  992. X
  993. X     assoc_value = *slot;
  994. X
  995. X     if ( (assoc_value) == 0)
  996. X       /* Nothing else has hashed to this slot. 
  997. X      We will put our string here. */
  998. X       { 
  999. X     *slot =  cell_from_mem(
  1000. X            (entry) H_getmem(table->value_size + length + sizeof('\0')
  1001. X                     + sizeof(entry*)));
  1002. X
  1003. X     *(mem_from_cell(*slot)) = rehash;
  1004. X     assoc_value = *slot;
  1005. X     strcpy(string_from_cell(assoc_value, table), string);
  1006. X     table->entries++;
  1007. X     return assoc_value;        /* <=========== */
  1008. X       }
  1009. X    
  1010. X     if (strcmp( string_from_cell(assoc_value,table), string) != 0)
  1011. X       {                /* Oops.. collision. */
  1012. X     rehash = REHASH(rehash,table);
  1013. X     goto look_at_slot;        /* <=========== */
  1014. X       }
  1015. X     else return assoc_value;        /* <=========== */
  1016. X
  1017. X   }
  1018. X    
  1019. X
  1020. X  
  1021. X
  1022. X
  1023. X}                    /* end assoc */
  1024. X
  1025. X/* Like assoc, except for non-null-terminated strings */
  1026. Xmem_cell
  1027. Xassocn( string, length, table)
  1028. X  register char* string;
  1029. X  register assoc_mem table;
  1030. X  register int length;
  1031. X{ /* assocn */
  1032. X
  1033. X  int hashval;
  1034. X
  1035. X  register int   rehash;
  1036. X  register entry assoc_value;
  1037. X
  1038. X  /* This is essential.  See assoc_internals.h */
  1039. X  if (table->entries >= table->size_div_2 - 1)
  1040. X    H_expand_table(table);
  1041. X
  1042. X  hashn(string, table->mask, length, &hashval);
  1043. X  rehash = hashval;
  1044. X
  1045. X look_at_slot:
  1046. X  {  register entry * slot = &((*(table->array))[rehash]);
  1047. X
  1048. X     assoc_value = *slot;
  1049. X
  1050. X     if ( (assoc_value) == 0)
  1051. X       /* Nothing else has hashed to this slot. 
  1052. X      We will put our string here. */
  1053. X       { 
  1054. X     *slot =  cell_from_mem(
  1055. X            (entry) H_getmem(table->value_size + length + sizeof('\0')
  1056. X                     + sizeof(entry*)));
  1057. X
  1058. X     *(mem_from_cell(*slot)) = rehash;
  1059. X     assoc_value = *slot;
  1060. X     strncpy(string_from_cell(assoc_value, table), string, length);
  1061. X     table->entries++;
  1062. X     return assoc_value;        /* <=========== */
  1063. X       }
  1064. X    
  1065. X     if (lstrncmp( string_from_cell(assoc_value,table), string, length) != 0)
  1066. X       {                /* Oops.. collision. */
  1067. X     rehash = REHASH(rehash,table);
  1068. X     goto look_at_slot;        /* <=========== */
  1069. X       }
  1070. X     else return assoc_value;        /* <=========== */
  1071. X
  1072. X   }
  1073. X    
  1074. X
  1075. X}                    /* end assocn */
  1076. X/* Like assoc, except for non-null-terminated strings, and folds cases. */
  1077. Xmem_cell
  1078. Xassocnf( string, length, table)
  1079. X  register char* string;
  1080. X  register assoc_mem table;
  1081. X  register int length;
  1082. X{ /* assocn */
  1083. X
  1084. X  int hashval;
  1085. X
  1086. X  register int   rehash;
  1087. X  register entry assoc_value;
  1088. X
  1089. X  /* This is essential.  See assoc_internals.h */
  1090. X  if (table->entries >= table->size_div_2 - 1)
  1091. X    H_expand_table(table);
  1092. X
  1093. X  hashnf(string, table->mask, length, &hashval);
  1094. X  rehash = hashval;
  1095. X
  1096. X look_at_slot:
  1097. X  {  register entry * slot = &((*(table->array))[rehash]);
  1098. X
  1099. X     assoc_value = *slot;
  1100. X
  1101. X     if ( (assoc_value) == 0)
  1102. X       /* Nothing else has hashed to this slot. 
  1103. X      We will put our string here. */
  1104. X       { 
  1105. X     *slot =  cell_from_mem(
  1106. X            (entry) H_getmem(table->value_size + length + sizeof('\0')
  1107. X                     + sizeof(entry*)));
  1108. X
  1109. X     *(mem_from_cell(*slot)) = rehash;
  1110. X     assoc_value = *slot;
  1111. X     strncpy(string_from_cell(assoc_value, table), string, length);
  1112. X     table->entries++;
  1113. X     return assoc_value;        /* <=========== */
  1114. X       }
  1115. X    
  1116. X     if (lstrncmpf( string_from_cell(assoc_value,table), string, length) != 0)
  1117. X       {                /* Oops.. collision. */
  1118. X     rehash = REHASH(rehash,table);
  1119. X     goto look_at_slot;        /* <=========== */
  1120. X       }
  1121. X     else return assoc_value;        /* <=========== */
  1122. X
  1123. X   }
  1124. X    
  1125. X}                    /* end assocnf */
  1126. X
  1127. X/* returns 0 iff a null-terminated string and counted string compare */
  1128. Xstatic
  1129. Xlstrncmp(nullterm, counted, len)
  1130. X  char* nullterm;
  1131. X  char* counted;
  1132. X{
  1133. X                
  1134. X  while( *nullterm && len && *nullterm++ == *counted++)
  1135. X    len--;
  1136. X  return !(len == 0 && *nullterm == 0);
  1137. X}
  1138. X
  1139. X/* returns 0 iff a null-terminated string and counted string compare */
  1140. X/* folds cases */
  1141. Xstatic
  1142. Xlstrncmpf(nullterm, counted, len)
  1143. X  char* nullterm;
  1144. X  char* counted;
  1145. X{
  1146. X                
  1147. X  while( *nullterm && len && LOWER(*nullterm) == LOWER(*counted))
  1148. X    {
  1149. X      len--;
  1150. X      nullterm++; counted++;
  1151. X    }
  1152. X  return !(len == 0 && *nullterm == 0);
  1153. X}
  1154. X
  1155. X
  1156. X
  1157. X/* Look up the mem_cell associated with a given name. */
  1158. X/* Returns NULL if not found.                  */
  1159. X
  1160. Xmem_cell
  1161. Xassoc_lookup( string, table)
  1162. X  register char* string;
  1163. X  register assoc_mem table;
  1164. X{
  1165. X  register entry retval;
  1166. X  int length;
  1167. X  int hashval;
  1168. X
  1169. X  hash(string, table->mask, &length, &hashval);
  1170. X
  1171. X  { register int  rehash = hashval;
  1172. X    register int * assoc_value = 0;
  1173. X
  1174. X    look_at_slot:
  1175. X    {  entry * slot = &((*(table->array))[rehash]);
  1176. X
  1177. X       assoc_value = *slot;
  1178. X
  1179. X       if ( (assoc_value) == 0)
  1180. X        /* Nothing has hashed to this slot. 
  1181. X           Lookup has come to a sorry end. */
  1182. X        { 
  1183. X           return assoc_value;  /* <=========== */
  1184. X        }
  1185. X    
  1186. X       if (strcmp( string_from_cell(assoc_value,table), string) == 0)
  1187. X        /*  An identical string was previously put in this slot.
  1188. X        **  We found it!
  1189. X        */
  1190. X            { 
  1191. X           return assoc_value;  /* <=========== */
  1192. X        }
  1193. X
  1194. X       /* collision... try next slot in the rehash orbit */
  1195. X       rehash = REHASH(rehash,table);
  1196. X       goto look_at_slot;        /* <=========== */
  1197. X    }
  1198. X
  1199. X  }
  1200. X
  1201. X
  1202. X} /* end assoc_lookup */
  1203. X
  1204. X
  1205. Xmem_cell
  1206. Xassocn_lookup( string, length, table)
  1207. X  register char* string;
  1208. X  register assoc_mem table;
  1209. X{
  1210. X  register entry retval;
  1211. X  int hashval;
  1212. X
  1213. X  hashn(string, table->mask, length, &hashval);
  1214. X  
  1215. X  { register int  rehash = hashval;
  1216. X    register int * assoc_value = 0;
  1217. X    
  1218. X  look_at_slot:
  1219. X    {  entry * slot = &((*(table->array))[rehash]);
  1220. X       
  1221. X       assoc_value = *slot;
  1222. X       
  1223. X       if ( (assoc_value) == 0)
  1224. X     /* Nothing has hashed to this slot. 
  1225. X        Lookup has come to a sorry end. */
  1226. X     { 
  1227. X       return assoc_value;  /* <=========== */
  1228. X     }
  1229. X       
  1230. X       if (lstrncmp( string_from_cell(assoc_value,table), string, length) == 0)
  1231. X     /*  An identical string was previously put in this slot.
  1232. X     **  We found it!
  1233. X     */
  1234. X     { 
  1235. X       return assoc_value;  /* <=========== */
  1236. X     }
  1237. X       
  1238. X       /* collision... try next slot in the rehash orbit */
  1239. X       rehash = REHASH(rehash,table);
  1240. X       goto look_at_slot;        /* <=========== */
  1241. X
  1242. X     }
  1243. X    
  1244. X  }
  1245. X
  1246. X
  1247. X} /* end assocn_lookup */
  1248. X
  1249. X
  1250. Xmem_cell
  1251. Xassocnf_lookup( string, length, table)
  1252. X  register char* string;
  1253. X  register assoc_mem table;
  1254. X{
  1255. X  register entry retval;
  1256. X  int hashval;
  1257. X
  1258. X  hashnf(string, table->mask, length, &hashval);
  1259. X  
  1260. X  { register int  rehash = hashval;
  1261. X    register int * assoc_value = 0;
  1262. X    
  1263. X  look_at_slot:
  1264. X    {  entry * slot = &((*(table->array))[rehash]);
  1265. X       
  1266. X       assoc_value = *slot;
  1267. X       
  1268. X       if ( (assoc_value) == 0)
  1269. X     /* Nothing has hashed to this slot. 
  1270. X        Lookup has come to a sorry end. */
  1271. X     { 
  1272. X       return assoc_value;  /* <=========== */
  1273. X     }
  1274. X       
  1275. X       if (lstrncmpf( string_from_cell(assoc_value,table), string, length) == 0)
  1276. X     /*  An identical string was previously put in this slot.
  1277. X     **  We found it!
  1278. X     */
  1279. X     { 
  1280. X       return assoc_value;  /* <=========== */
  1281. X     }
  1282. X       
  1283. X       /* collision... try next slot in the rehash orbit */
  1284. X       rehash = REHASH(rehash,table);
  1285. X       goto look_at_slot;        /* <=========== */
  1286. X
  1287. X     }
  1288. X    
  1289. X  }
  1290. X
  1291. X
  1292. X} /* end assocnf_lookup */
  1293. X
  1294. X
  1295. X
  1296. X
  1297. X/* This routine hashes a string and counts the number of chars in it.   */
  1298. X/* The hash value is a function of the table size.             */
  1299. X
  1300. Xstatic
  1301. Xhash(string, mask, lenp, hashp)
  1302. X  char* string;
  1303. X  int mask;     /* Is table size minus one. */
  1304. X  int *lenp;
  1305. X  int *hashp;
  1306. X
  1307. X{
  1308. X  register int len = 0;
  1309. X  register int hash = 0;
  1310. X  register char* cursor = string;
  1311. X
  1312. X  len = 0;
  1313. X  hash = 0;
  1314. X
  1315. X  while (*cursor)
  1316. X    { len++;
  1317. X      hash += ((hash << 1) + *cursor++);
  1318. X    }
  1319. X  *hashp = hash & mask;
  1320. X  *lenp = len;  
  1321. X
  1322. X
  1323. X} /* hash */
  1324. X
  1325. X/* Like hash, except for counted (not null-terminated) strings */
  1326. Xstatic
  1327. Xhashn(string, mask, len, hashp)
  1328. X  char* string;
  1329. X  int mask;     /* Is table size minus one. */
  1330. X  int len;
  1331. X  int *hashp;
  1332. X
  1333. X{
  1334. X  register int hash = 0;
  1335. X  register char* cursor = string;
  1336. X
  1337. X  hash = 0;
  1338. X
  1339. X  while (len--)
  1340. X    {
  1341. X      hash += ((hash << 1) + *cursor++);
  1342. X    }
  1343. X  
  1344. X  *hashp = hash & mask;
  1345. X
  1346. X} /* hashn*/
  1347. X/* Like hash, except for counted (not null-terminated) strings */
  1348. X/* Folds cases. */
  1349. Xstatic
  1350. Xhashnf(string, mask, len, hashp)
  1351. X  char* string;
  1352. X  int mask;     /* Is table size minus one. */
  1353. X  int len;
  1354. X  int *hashp;
  1355. X
  1356. X{
  1357. X  register int hash = 0;
  1358. X  register char* cursor = string;
  1359. X
  1360. X  hash = 0;
  1361. X
  1362. X  while (len--)
  1363. X    {
  1364. X      hash += ((hash << 1) + LOWER(*cursor));
  1365. X      cursor++;
  1366. X    }
  1367. X  
  1368. X  *hashp = hash & mask;
  1369. X
  1370. X} /* hashn*/
  1371. X
  1372. X
  1373. X
  1374. X
  1375. X/* "Safe" memory allocation routine... zeros out memory obtained. */
  1376. X
  1377. Xstatic int*
  1378. XH_getmem(size)
  1379. X  int size;
  1380. X{
  1381. X  int * retval = (int*)calloc(size, sizeof(char));
  1382. X  if (retval == (int*)0)
  1383. X    {
  1384. X    fprintf(PANIC_FILE, "RESOURCE FAILURE: Assoc out of memory. (%d)\n",
  1385. X        size);
  1386. X    exit(1);
  1387. X    }
  1388. X  else return retval;
  1389. X
  1390. X}
  1391. X
  1392. X
  1393. X
  1394. X
  1395. X
  1396. X
  1397. X/* When a table becomes half full, we double its size.  (The
  1398. X** orbit of the rehash function touches exactly half the slots.)
  1399. X**
  1400. X*/
  1401. X
  1402. Xstatic
  1403. XH_expand_table(table)
  1404. X  register assoc_mem table;
  1405. X{
  1406. X  register hash_table * old_table = table->array;
  1407. X  register int old_size = table->size;
  1408. X  table->size_div_2 = table->size;
  1409. X  table->size = table->size * 2;
  1410. X  table->mask = table->size -1;
  1411. X
  1412. X  table->array = (hash_table *)H_getmem(table->size * (sizeof (mem_cell)));
  1413. X
  1414. X  /* Move the members from the old small table to be new big one. */
  1415. X  { register int recno;
  1416. X
  1417. X    for (recno = 0; recno < old_size; recno++)
  1418. X      if ( (*old_table)[recno] != (entry)0)
  1419. X        H_reassoc( (*old_table)[recno], table );
  1420. X  }
  1421. X
  1422. X  cfree (old_table);
  1423. X}
  1424. X
  1425. X
  1426. X
  1427. X
  1428. X
  1429. X/* This routine is a little like assoc. It is used by expand_table() to
  1430. X** put entries which were in table which overflowed into the new larger one.
  1431. X** Used by assoc_free() to put entries back into the table which might
  1432. X** have originally been bumped down the rehash orbit by the entry being
  1433. X** removed.
  1434. X*/
  1435. X
  1436. Xstatic
  1437. XH_reassoc( rec, table)
  1438. X  register entry rec;
  1439. X  register assoc_mem table;
  1440. X{
  1441. X  register entry retval;
  1442. X  register char* string = string_from_cell(rec, table);
  1443. X  int length;
  1444. X  int hashval;
  1445. X
  1446. X  hash(string, table->mask, &length, &hashval);
  1447. X
  1448. X  { register int  rehash = hashval;
  1449. X
  1450. X    look_at_slot:
  1451. X    {  register entry * slot = &((*(table->array))[rehash]);
  1452. X
  1453. X       if ( (*slot) == 0)
  1454. X        { 
  1455. X          *slot = rec;
  1456. X          *(mem_from_cell(*slot)) = rehash;
  1457. X
  1458. X          return;        /* <========= */
  1459. X        }
  1460. X    
  1461. X       rehash = REHASH(rehash,table);
  1462. X       goto look_at_slot;      /* <========= */
  1463. X    }
  1464. X    
  1465. X  }
  1466. X
  1467. X
  1468. X} /* H_reassoc */
  1469. X
  1470. X
  1471. X
  1472. X
  1473. X/* This is a sequencer for a table.  You give it a pointer to an
  1474. X** integer variable which you have initialized to zero, and it gives
  1475. X** you a member of the table and modifies the variable.  Call it
  1476. X** again without changing the variable and it gives you the next one, etc...
  1477. X**
  1478. X**    { int handle = 0;
  1479. X**      mem_cell member;
  1480. X**
  1481. X**      do { member = assoc_seq(table, &handle);
  1482. X**           if (member != NULL) process(member);
  1483. X**         }
  1484. X**      while (member != NULL);
  1485. X**    }
  1486. X**
  1487. X**
  1488. X** DO NOT ADD OR DELETE MEMBERS BETWEEN RELATED CALLS TO assoc_seq().
  1489. X** To do so will wreak non-determinancy if the assoc() caused the
  1490. X** table to expand, or if the assoc_free() caused a member to be
  1491. X** moved back up the rehash chain.  You might very easily miss some
  1492. X** members.
  1493. X**
  1494. X*/
  1495. X
  1496. Xmem_cell
  1497. Xassoc_seq(table, num)
  1498. X  register assoc_mem table;
  1499. X  register int *num;
  1500. X{
  1501. X  register hash_table * hash_tab = table->array;
  1502. X  register int size = table->size;
  1503. X  /* Standard linear search algorithm looks for next non-empty slot
  1504. X  ** at index *num or further down.
  1505. X  */
  1506. X  for (; (*num) < size; (*num)++)
  1507. X    if ( (*hash_tab)[*num] != (entry)0)
  1508. X    { mem_cell retval = (*hash_tab)[*num];
  1509. X      (*num)++;
  1510. X      return retval;
  1511. X    }
  1512. X
  1513. X  return 0;
  1514. X
  1515. X}
  1516. X
  1517. X
  1518. X
  1519. X/*
  1520. X** This procedure removes a member from a table.
  1521. X*/
  1522. X
  1523. Xassoc_free(cell, table)
  1524. X  mem_cell cell;
  1525. X  assoc_mem table;
  1526. X{
  1527. X  /* Invariant: next_slot_num and next_slot point to entries in the rehash
  1528. X  ** orbit of the cell being removed.  They start out pointing to the
  1529. X  ** slot of the condemned cell itself:
  1530. X  */
  1531. X  register next_slot_num = *(mem_from_cell(cell));
  1532. X  register entry *next_slot = &((*(table->array))[next_slot_num]);
  1533. X
  1534. X  /* Remove the condemned cell. */
  1535. X  free(mem_from_cell(*next_slot));
  1536. X  *next_slot = 0; /* Splat! got it. */
  1537. X  table->entries -= 1;
  1538. X
  1539. X  /* The entry we just removed might have caused some other entries
  1540. X  ** to be "bumped down the rehash orbit" when they were installed in
  1541. X  ** the table.  If that was the case, they can not now be found unless
  1542. X  ** they are moved to their (now) proper position in the table.
  1543. X  */
  1544. X   while(
  1545. X      next_slot_num = REHASH(next_slot_num,table),
  1546. X      next_slot = &((*(table->array))[next_slot_num]),
  1547. X      (*next_slot != 0)
  1548. X    )
  1549. X     { entry mover = *next_slot;
  1550. X       *next_slot = 0;
  1551. X       H_reassoc(mover, table);
  1552. X     }
  1553. X  
  1554. X}/* assoc_free */
  1555. X
  1556. X
  1557. X
  1558. X/* Deletes a table and returns 0 if the table is empty.
  1559. X** Does not delete table, but returns number of entries remaining if
  1560. X** table is not empty.
  1561. X*/
  1562. X
  1563. Xint
  1564. Xassoc_mem_free(table)
  1565. X  assoc_mem table;
  1566. X{
  1567. X  if (table->entries == 0)
  1568. X    {  free(table->array);
  1569. X       free(table);
  1570. X       return 0;
  1571. X    }
  1572. X  else return table->entries;
  1573. X
  1574. X}
  1575. X
  1576. X/* Deletes all members in a table, then removes the table. */
  1577. X
  1578. Xassoc_mem_remove(table)
  1579. X  assoc_mem table;
  1580. X{ register int num = 0;
  1581. X  register hash_table * hash_tab = table->array;
  1582. X  register int size = table->size;
  1583. X  for (; (num) < size; (num)++)
  1584. X    if ( (*hash_tab)[num] != (entry)0)
  1585. X    { 
  1586. X          free(mem_from_cell((*hash_tab)[num]));
  1587. X    }
  1588. X
  1589. X
  1590. X  free(table->array);
  1591. X  free(table);
  1592. X
  1593. X}
  1594. END_OF_assoc.c
  1595. if test 17401 -ne `wc -c <assoc.c`; then
  1596.     echo shar: \"assoc.c\" unpacked with wrong size!
  1597. fi
  1598. # end of overwriting check
  1599. fi
  1600. if test -f assoc.doc -a "${1}" != "-c" ; then 
  1601.   echo shar: Will not over-write existing file \"assoc.doc\"
  1602. else
  1603. echo shar: Extracting \"assoc.doc\" \(3671 characters\)
  1604. sed "s/^X//" >assoc.doc <<'END_OF_assoc.doc'
  1605. X
  1606. X
  1607. X
  1608. X#include "assoc.h"
  1609. X
  1610. X
  1611. Xassoc_mem
  1612. Xnew_assoc_mem( cell_size );
  1613. X  int cell_size;
  1614. X
  1615. Xmem_cell
  1616. Xassoc( string, table );
  1617. X  char*     string;
  1618. X  assoc_mem table;
  1619. X
  1620. Xmem_cell
  1621. Xassocn( string, length, table );
  1622. X  char*     string;
  1623. X  int         length;
  1624. X  assoc_mem table;
  1625. X
  1626. Xmem_cell
  1627. Xassocnf( string, length, table );
  1628. X  char*     string;
  1629. X  int         length;
  1630. X  assoc_mem table;
  1631. X
  1632. Xmem_cell
  1633. Xassoc_lookup( string, table );
  1634. X  char* string;
  1635. X  assoc_mem table;
  1636. X
  1637. Xmem_cell
  1638. Xassocn_lookup( string, length, table)
  1639. X  register char* string;
  1640. X  register assoc_mem table;
  1641. X
  1642. Xchar*
  1643. Xstring_from_cell(cell,table)  /* Macro */
  1644. X   mem_cell cell;
  1645. X   assoc_mem table;
  1646. X
  1647. Xmem_cell
  1648. Xcell_from_string(string, table) /* Macro */
  1649. X  char* string;
  1650. X  assoc_mem table;
  1651. X
  1652. Xmem_cell
  1653. Xassoc_seq( table, &seq  )
  1654. X  assoc_mem table;
  1655. X  int seq = 0;
  1656. X
  1657. X
  1658. Xassoc_free( cell, table );
  1659. X  mem_cell cell;
  1660. X  assoc_mem table;
  1661. X
  1662. Xint
  1663. Xassoc_mem_free( table )
  1664. X  assoc_mem table;
  1665. X
  1666. Xassoc_mem_remove(table)
  1667. X  assoc_mem table;
  1668. X
  1669. X
  1670. X
  1671. XAn associative memory is identified by a value of type "assoc_mem".  To
  1672. Xobtain one, use the procedure new_assoc_mem().
  1673. X
  1674. XTo obtain a mem_cell associated with a string use the procedure assoc():
  1675. XCaveat: Do not call assoc() when you have a sequencer active. (See below.)
  1676. Xassocn() is like assoc(), except it uses counted strings as input parameters,
  1677. Xrather than null-terminated strings.  assocnf() is like assocn, except
  1678. Xthat it maps strings to lower-case for indexing.
  1679. X
  1680. XSometimes it is desirable to add a new association, if none exists, but
  1681. Xto recognize the situation if an association had been made previously.
  1682. XTo this purpose, assoc() will return the mem_cell previously associated
  1683. Xwith a string if there was one, but will zero out a new mem_cell when
  1684. Xit allocates one. Thus one may determine whether or not a mem_cell is
  1685. Xa new one by setting a bit in a mem_cell when it is first associtated
  1686. Xwith a string.  The demo program demonstrates this technique.
  1687. X
  1688. XYou may put pointers into the mem_cells.  You can use this technique to
  1689. Xassociate strings with LIFO's for example.  By doing so, you may
  1690. Xassociate multiple values, perhaps of different sizes, with one string.
  1691. X
  1692. X
  1693. XTo look up a mem_cell previously associated with a string, use the
  1694. Xprocedure assoc_lookup().  Also, see cell_from_string() below.
  1695. Xassocn_lookup() is like assoc_lookup(), except that its input parameter
  1696. Xis a counted string, rather than a null-terminated string.
  1697. X
  1698. X
  1699. X
  1700. XTo obtain the string associated with a mem_cell, use the macro
  1701. Xstring_from_cell():
  1702. X
  1703. X
  1704. XThe value returned by string_from_cell is a pointer to the string which
  1705. Xis internal to the table.  Thus two strings obtained in this manner may
  1706. Xbe compared for equality using = rather than strcmp, which of course is
  1707. Xmuch slower.   Furthermore, if one has a string obtained from
  1708. Xstring_from_cell, one may use the macro cell_from_string() instead of
  1709. Xlookup().  cell_from_string() is faster.
  1710. X
  1711. X
  1712. Xassoc_seq() sequences through a table, returning the cells found there in a 
  1713. Xnon-deterministic order.  If you put cells into the table as you
  1714. Xare sequencing through, the sequencer is likely to miss some values,
  1715. Xso don't DO that! Set "seq" to zero before the first call, then don't touch 
  1716. Xit.  The sequencer is finished when it returns NULL;
  1717. X
  1718. Xassoc_free() removes a memory cell from a table, and frees its memory.
  1719. X
  1720. Xassoc_mem_free() deallocates the memory associated with an assoc_mem table 
  1721. Xand returns zero, if the table was empty.  Otherwize it just returns the 
  1722. Xnumber of entries remaining in the table.
  1723. X
  1724. X
  1725. Xassoc_mem_remove() deletes all members from a table, then removes the table.
  1726. X
  1727. XCaveat:
  1728. XUse only "assoc_free" and "assoc_mem_free" to deallocation cells and tables.
  1729. XUsing "free" will crash your program if you are lucky.
  1730. END_OF_assoc.doc
  1731. if test 3671 -ne `wc -c <assoc.doc`; then
  1732.     echo shar: \"assoc.doc\" unpacked with wrong size!
  1733. fi
  1734. # end of overwriting check
  1735. fi
  1736. if test -f assoc_internals.h -a "${1}" != "-c" ; then 
  1737.   echo shar: Will not over-write existing file \"assoc_internals.h\"
  1738. else
  1739. echo shar: Extracting \"assoc_internals.h\" \(1498 characters\)
  1740. sed "s/^X//" >assoc_internals.h <<'END_OF_assoc_internals.h'
  1741. X
  1742. X/**********************************************************************\
  1743. X**                                      **
  1744. X** internal data types... not for use by the mortal man.. subject to  **
  1745. X** changes..  information hiding and all that, don't you know.          **
  1746. X**                                      **
  1747. X\**********************************************************************/
  1748. X
  1749. Xtypedef int* H_memory_cell;/* pointers to user's memory area. */
  1750. X
  1751. Xtypedef H_memory_cell entry;  
  1752. X
  1753. Xtypedef entry hash_table[];
  1754. X
  1755. Xtypedef struct assoc_mem_rec
  1756. X    { hash_table *array; 
  1757. X       int value_size;   /* User defined size of data values; */
  1758. X      int size;      /* Number of slots in table.. power of 2 */
  1759. X      int size_div_2; /* always = size / 2 */
  1760. X      int mask;      /* always = size-1, for calculating (num mod size)*/
  1761. X      int entries;    /* number of entries in assoc mem */
  1762. X    }
  1763. X     * assoc_memory;
  1764. X
  1765. X
  1766. X/* Get unique stored string associated with a memory cell */
  1767. X
  1768. X#define str_from_cell(cell,table) \
  1769. X    ((char*) (((char*) (cell))  + (table)->value_size))
  1770. X
  1771. X/* Get memory cell associated with a string returned from string_from_cell*/
  1772. X
  1773. X#define cell_from_str(string,table) \
  1774. X    ((int*)  (((char*) (string)) - (table)->value_size))
  1775. X
  1776. X#define mem_from_cell(cell) ((int*)    ((char*)(cell) - sizeof(entry)))
  1777. X#define cell_from_mem(mem)  ((mem_cell)((char*)(mem)  + sizeof(entry)))
  1778. X
  1779. X#define INIT_TABLE_SIZE 8 /* Must be a power of two */
  1780. X/*************************************************************************
  1781. X*************************************************************************/
  1782. X
  1783. END_OF_assoc_internals.h
  1784. if test 1498 -ne `wc -c <assoc_internals.h`; then
  1785.     echo shar: \"assoc_internals.h\" unpacked with wrong size!
  1786. fi
  1787. # end of overwriting check
  1788. fi
  1789. if test -f assoc.h -a "${1}" != "-c" ; then 
  1790.   echo shar: Will not over-write existing file \"assoc.h\"
  1791. else
  1792. echo shar: Extracting \"assoc.h\" \(2429 characters\)
  1793. sed "s/^X//" >assoc.h <<'END_OF_assoc.h'
  1794. X#ifndef ASSOC_DEFD
  1795. X#define ASSOC_DEFD
  1796. X
  1797. X#include "assoc_internals.h"
  1798. X
  1799. X
  1800. X/***********************************************************************
  1801. X**
  1802. X**  See documentation in "assoc.c"
  1803. X**
  1804. X***********************************************************************/
  1805. X
  1806. X/*****/
  1807. X/* A handle on an associative memory */
  1808. X#define assoc_mem assoc_memory
  1809. X
  1810. X/*****/
  1811. X/* Raw memory pointers from an associative memory. Do not use free() on
  1812. X** them.  See assoc_free(). */
  1813. X#define mem_cell H_memory_cell
  1814. X
  1815. X/*****/
  1816. X/***** Get unique stored string associated with a memory cell which
  1817. X       was returned by assoc(), assoc_lookup() or assoc_seq(). */
  1818. X#define string_from_cell(cell,table)  str_from_cell(cell,table)
  1819. X
  1820. X
  1821. X/*****/
  1822. X/***** Get memory cell associated with a string which was returned by
  1823. X**     string_from_cell  */
  1824. X#define cell_from_string(string,table) cell_from_str(string,table)
  1825. X
  1826. X
  1827. X
  1828. X/*****/
  1829. X/***** Gets new assoc mem */
  1830. Xassoc_mem
  1831. Xnew_assoc_mem( /* cell_size */ );
  1832. X
  1833. X
  1834. X
  1835. X/*****/
  1836. X/***** Associates a new cell with a given string. */
  1837. Xmem_cell
  1838. Xassoc(/* string, table */);
  1839. X
  1840. X/* Is like assoc, except uses counted string, rather that null-terminated */
  1841. Xmem_cell
  1842. Xassocn(/*string, string_length, table */);
  1843. X
  1844. X/*****/
  1845. X/***** Looks for a cell previously associated with a given string */   
  1846. Xmem_cell
  1847. Xassoc_lookup(/* string, table */);
  1848. X
  1849. X/* Like assoc_lookup, except uses counted string, rather than null-
  1850. X** terminated string
  1851. X*/
  1852. Xmem_cell
  1853. Xassocn_lookup(/* string, length, table */);
  1854. X
  1855. X
  1856. X/*****/
  1857. X/***** Removes a memory cell from a table */
  1858. Xassoc_free(/* cell, table */ );
  1859. X
  1860. X/*****/
  1861. X/* Sequences through a table, returning the cells found there in a 
  1862. X** non-deterministic order.  If you put cells into the table as you
  1863. X** are sequencing through, the sequencer may find the added value or
  1864. X** it may not, so you probably do not want to do that.  Set the variable
  1865. X** "seq" to zero before the first call, then don't touch it.  The
  1866. X** sequencer is finished when it returns NULL;
  1867. X*/
  1868. Xmem_cell
  1869. Xassoc_seq( /* table, &seq */ );
  1870. X
  1871. X
  1872. X/*****/
  1873. X/* Deallocates the memory associated with an assoc_mem table and returns zero,
  1874. X** if the table was empty.  Otherwize it just returns the number of entries
  1875. X** remaining in the table.
  1876. X*/
  1877. Xint
  1878. Xassoc_mem_free( /* table */ );
  1879. X
  1880. X/*****/
  1881. X/***** Empties a table, then removes it. */
  1882. Xassoc_mem_remove(/* table */ );
  1883. X
  1884. X
  1885. X
  1886. X/*****/
  1887. X/***** returns number of entries currently in table */
  1888. X#define assoc_num_entries(table) (table->entries)
  1889. X
  1890. X#endif ASSOC_DEFD
  1891. END_OF_assoc.h
  1892. if test 2429 -ne `wc -c <assoc.h`; then
  1893.     echo shar: \"assoc.h\" unpacked with wrong size!
  1894. fi
  1895. # end of overwriting check
  1896. fi
  1897. if test -f which.c -a "${1}" != "-c" ; then 
  1898.   echo shar: Will not over-write existing file \"which.c\"
  1899. else
  1900. echo shar: Extracting \"which.c\" \(1840 characters\)
  1901. sed "s/^X//" >which.c <<'END_OF_which.c'
  1902. X#include <sys/param.h>
  1903. X#include <sys/stat.h>
  1904. X
  1905. X
  1906. X/* This does the equivalent of /bin/which.  That is, given a filename,
  1907. X** it searches directories named in the environment variable PATH, until
  1908. X** it finds a file with that filename.
  1909. X*/
  1910. X#define copy_of(name) ((char*) sprintf(malloc(strlen(name)+1), "%s", name))
  1911. X
  1912. Xstatic
  1913. Xexists(filename)
  1914. X  char* filename;
  1915. X{
  1916. X  struct stat buffer;
  1917. X  return(stat(filename, &buffer) != -1);
  1918. X
  1919. X}
  1920. X
  1921. X/* The PATH string looks something like this:
  1922. X**
  1923. X** .:/u/djones/bin:/usr/local/bin:/usr/mega/bin:/u/mega/bin
  1924. X**
  1925. X**
  1926. X** except probably longer.
  1927. X*/
  1928. X
  1929. Xchar*
  1930. Xwhich(file)
  1931. X  char* file;
  1932. X{
  1933. X
  1934. X  if(*file == '/') return copy_of(file);
  1935. X
  1936. X  {  char* search = (char*)getenv("PATH");
  1937. X
  1938. X     if(search == 0)
  1939. X       search = ".:~/bin:/usr/mega/bin:/usr/local/bin:/usr/new:/usr/ucb:/usr/bin:/bin:/usr/hosts:/usr/games";
  1940. X
  1941. X     { register char* ptr = search;
  1942. X       
  1943. X       while(*ptr)
  1944. X     { char  name[MAXPATHLEN];
  1945. X       register char* next = name;
  1946. X        
  1947. X       /* copy directory name into [name] */
  1948. X       while(*ptr && *ptr != ':') *next++ = *ptr++;
  1949. X       if(*ptr) ptr++;
  1950. X       
  1951. X       *next++ = '/'; /* separates directory name and filename */
  1952. X       
  1953. X       /* copy filename into [name] */
  1954. X       { register char* ptr2 = file;
  1955. X         while(*ptr2) *next++ = *ptr2++;
  1956. X       }
  1957. X       
  1958. X       *next = '\0';
  1959. X       
  1960. X       { char* afile = (char*)(name);
  1961. X         if(exists(afile)) return (afile);
  1962. X         free(afile);
  1963. X       }
  1964. X       
  1965. X     }
  1966. X       
  1967. X     }
  1968. X     return file;
  1969. X   }
  1970. X}
  1971. X
  1972. X#undef binwhich
  1973. X#ifdef binwhich
  1974. Xmain(argc, argv)
  1975. X  char** argv;
  1976. X{
  1977. X
  1978. X  argc--; argv++;
  1979. X
  1980. X  while (argc)
  1981. X    { char* path = which(*argv);
  1982. X      if(path)
  1983. X    {
  1984. X      printf("%s\n", path);
  1985. X      free(path);
  1986. X    }
  1987. X      else
  1988. X    { char* ptr = search;
  1989. X      printf("no %s in ", *argv);
  1990. X      while(*ptr)
  1991. X        { putchar(*ptr==':' ? ' ' : *ptr);
  1992. X          ptr++;
  1993. X        }
  1994. X      putchar('\n');
  1995. X    }
  1996. X      argc--; argv++; 
  1997. X    }
  1998. X  exit(0);
  1999. X}
  2000. X#endif binwhich
  2001. END_OF_which.c
  2002. if test 1840 -ne `wc -c <which.c`; then
  2003.     echo shar: \"which.c\" unpacked with wrong size!
  2004. fi
  2005. # end of overwriting check
  2006. fi
  2007. if test -f smalloc.c -a "${1}" != "-c" ; then 
  2008.   echo shar: Will not over-write existing file \"smalloc.c\"
  2009. else
  2010. echo shar: Extracting \"smalloc.c\" \(261 characters\)
  2011. sed "s/^X//" >smalloc.c <<'END_OF_smalloc.c'
  2012. Xstatic char error[] = "Out of memory\n";
  2013. X
  2014. Xint*
  2015. Xsmalloc(size) /* "Safe" alloc */
  2016. X{  int* retval = (int*)calloc(1,size);
  2017. X
  2018. X   if (retval == 0)
  2019. X    { write(2, error, sizeof(error));
  2020. X      exit(-1);
  2021. X    }
  2022. X   else return retval;
  2023. X}
  2024. X
  2025. X
  2026. X
  2027. Xsfree(ptr)
  2028. X{
  2029. X  if (ptr != 0) free(ptr);
  2030. X}
  2031. END_OF_smalloc.c
  2032. if test 261 -ne `wc -c <smalloc.c`; then
  2033.     echo shar: \"smalloc.c\" unpacked with wrong size!
  2034. fi
  2035. # end of overwriting check
  2036. fi
  2037. if test -f argv.c -a "${1}" != "-c" ; then 
  2038.   echo shar: Will not over-write existing file \"argv.c\"
  2039. else
  2040. echo shar: Extracting \"argv.c\" \(4590 characters\)
  2041. sed "s/^X//" >argv.c <<'END_OF_argv.c'
  2042. X#include <ctype.h>
  2043. X#include <stdio.h>
  2044. X
  2045. X/***********************************************************************
  2046. X**
  2047. X** These routines build argv's.  An "argv" is a null-terminated array
  2048. X** of pointers to strings.  Argv's are often declared as char** or
  2049. X** char* foo [];
  2050. X** 
  2051. X** char***
  2052. X** argv_new() 
  2053. X**
  2054. X**    returns a structure which is a "scaffold" for building up
  2055. X**    an argv. At any point, the structure will contain an argv in its
  2056. X**    first field.  If it overflows, a new, larger one is substituted,
  2057. X**    and the old one discarded.  So don't keep direct references to the argv
  2058. X**    unless you are not going to put any more stuff into it.
  2059. X**
  2060. X**    Say 
  2061. X**         char*** scaffold = (char***)argv_new();
  2062. X**    
  2063. X**    Then, when the argv is completed, dereference it...
  2064. X** 
  2065. X**         char** complete_argv = *scaffold;
  2066. X**
  2067. X**    Then free the scaffold if you wish...
  2068. X**
  2069. X**         cfree(scaffold);
  2070. X**
  2071. X**    The argv itself is also allocated by calloc, and may be cfree()'d when
  2072. X**    it is no longer needed.
  2073. X**
  2074. X**    argv_new() returns 0 if it runs out of memory.
  2075. X**
  2076. X** 
  2077. X** int
  2078. X** argv_put(scaffold, arg) 
  2079. X**    char*** scaffold;
  2080. X**    char* arg;
  2081. X**
  2082. X**    puts an additional arg into an argv, increasing the size
  2083. X**    if necessary. Returns 0 on success, -1 if it runs out of memory.
  2084. X**
  2085. X** char**
  2086. X** argv_from_str(str)
  2087. X**   char* str
  2088. X**
  2089. X**    Parses a string and builds an argv from it.  It
  2090. X**    recognizes quote-marks and escapes (\).
  2091. X**
  2092. X**    For example,
  2093. X**
  2094. X**       foo bar  "foo bar"  '\'foo\''  '"foo"'
  2095. X**
  2096. X**    gets parsed into
  2097. X**
  2098. X**       foo
  2099. X**       bar
  2100. X**       foo bar
  2101. X**       'foo'
  2102. X**       "foo"
  2103. X**       (0)
  2104. X**
  2105. X**    The argv and its components are all allocated by calloc().
  2106. X**    Returns 0 if it runs out of memory.
  2107. X**    
  2108. X**
  2109. X************************************************************************/
  2110. X
  2111. X
  2112. X
  2113. Xstruct argv_rec
  2114. X  { char** value;
  2115. X    int size;
  2116. X    int place;
  2117. X  };
  2118. X
  2119. X
  2120. Xargv_put(argv, str)
  2121. X  struct argv_rec * argv;
  2122. X  char* str;
  2123. X{
  2124. X  if (argv->place + 1 == argv->size) /* oops.. overflow. */
  2125. X    {
  2126. X      char** old_argv = argv->value;
  2127. X      int old_size = argv->size;
  2128. X
  2129. X      argv->size = argv->size *2;
  2130. X      argv->value = (char**)calloc(1, argv->size*sizeof(char*));
  2131. X      if(argv->value == 0) { return -1; }
  2132. X      bcopy(old_argv, argv->value, old_size * sizeof(char*));
  2133. X      free(old_argv);
  2134. X    }
  2135. X
  2136. X  argv->value[argv->place] = str;
  2137. X  argv->place++;
  2138. X
  2139. X  return 0;
  2140. X
  2141. X}
  2142. X
  2143. X
  2144. Xstruct argv_rec *
  2145. Xargv_new()
  2146. X{
  2147. X  struct argv_rec* retval = 
  2148. X    (struct argv_rec*) calloc(1,sizeof(struct argv_rec));
  2149. X  if (retval == 0) return 0;
  2150. X
  2151. X  retval->value = (char**)calloc(1, 2*sizeof(char*));
  2152. X  if(retval->value == 0) { free(retval); return 0; }
  2153. X
  2154. X  retval->size = 2;
  2155. X  retval->place = 0;
  2156. X
  2157. X  return retval;
  2158. X}
  2159. X
  2160. X
  2161. Xstatic char*
  2162. Xstrip(strp)
  2163. X  char** strp;
  2164. X{
  2165. X  char* str = strp? *strp: 0;
  2166. X  char* buffer;
  2167. X  char  quote = 0;
  2168. X  char* next_p;
  2169. X
  2170. X  if(str == 0 || *str == 0) return 0;
  2171. X
  2172. X  buffer = (char*)malloc(strlen(str)+1);
  2173. X  if(buffer == 0) return 0;
  2174. X
  2175. X  next_p  = buffer;
  2176. X
  2177. X  while (isspace(*str)) str++;
  2178. X
  2179. X  if(*str == '\'' || *str == '"' ) quote = *str++;
  2180. X
  2181. X  while(*str && !(isspace(*str) && !quote) && !(quote && *str == quote))
  2182. X    {
  2183. X      if(*str == '\\') str++;
  2184. X      *next_p++ = *str++;
  2185. X    }
  2186. X
  2187. X  if(*str && (quote && *str == quote) ) str++; /* skip end-quote */
  2188. X
  2189. X  *next_p = 0;
  2190. X  { char* retval = (char*)calloc(1, strlen(buffer) +1 );
  2191. X    if (retval) sprintf(retval, "%s", buffer);
  2192. X    free(buffer);
  2193. X    *strp = str;
  2194. X    return retval;
  2195. X  }
  2196. X}
  2197. X
  2198. X
  2199. Xchar**
  2200. Xargv_from_str(str)
  2201. X  char* str;
  2202. X{
  2203. X  struct argv_rec* argv;
  2204. X  char* next_arg;
  2205. X  extern errno;
  2206. X
  2207. X  errno = 0;
  2208. X
  2209. X  argv = argv_new();
  2210. X  if(argv == 0) return 0;
  2211. X
  2212. X  while( (next_arg = strip(&str)) != 0)
  2213. X    { argv_put(argv, next_arg);
  2214. X    }
  2215. X
  2216. X  { char** retval = argv->value;
  2217. X    free(argv);
  2218. X    return retval;
  2219. X  }
  2220. X  
  2221. X  
  2222. X}
  2223. X
  2224. Xfprintf_argv(fp,argv)
  2225. X  FILE * fp;
  2226. X  char** argv;
  2227. X{
  2228. X  if(argv)
  2229. X    while(*argv) fprintf(fp, "%s\n", *argv++);
  2230. X}
  2231. X
  2232. Xprintf_argv(argv)
  2233. X  char** argv;
  2234. X{
  2235. X  if(argv)
  2236. X    while(*argv) printf("%s\n", *argv++);
  2237. X}
  2238. X
  2239. Xint strcmp();
  2240. X
  2241. Xstatic
  2242. Xalcomp(p,q)
  2243. X  char**p;
  2244. X  char**q;
  2245. X{
  2246. X  return strcmp(*p,*q);
  2247. X}
  2248. X
  2249. Xsort_argv(argc, argv)
  2250. X  char** argv;
  2251. X{
  2252. X
  2253. X  qsort(argv, argc, sizeof(char*), alcomp );
  2254. X
  2255. X}
  2256. X
  2257. X
  2258. X#undef testing
  2259. X#ifdef testing
  2260. X#include <stdio.h>
  2261. Xmain(argc, argv)
  2262. X  char** argv;
  2263. X{
  2264. X  char  buf[256];
  2265. X  char** argy;
  2266. X  int argk = 0;
  2267. X  char** aargh;
  2268. X  scanf("%[^\n]", buf);
  2269. X  argy = argv_from_str(buf);
  2270. X
  2271. X  aargh = argy;
  2272. X
  2273. X  while(*argy) { printf("%s\n", *argy++ ); fflush(stdout); }
  2274. X  {
  2275. X    char** p = aargh;
  2276. X    while(*p++) argk++;
  2277. X  }
  2278. X  sort_argv(argk, aargh);
  2279. X  while(*aargh) { printf("%s\n", *aargh++ ); fflush(stdout); }
  2280. X}
  2281. X#endif testing
  2282. END_OF_argv.c
  2283. if test 4590 -ne `wc -c <argv.c`; then
  2284.     echo shar: \"argv.c\" unpacked with wrong size!
  2285. fi
  2286. # end of overwriting check
  2287. fi
  2288. echo shar: End of shell archive.
  2289. exit 0
  2290.  
  2291.  
  2292.  
  2293.